#include <unistd.h>
#include "seqiot.h"
#include "hisdata.h"

void block_head_init(block_head_t *self, block_type_e type, time_t timestamp) {
    self->bof[0] = BOF;
    self->bof[1] = EOF;
    self->type = type;
    self->ver = 0;
    self->enc = 0;
    self->_res = 0;
    self->timestamp = timestamp;
}

void block_tail_init(block_tail_t *self, uint16_t cs) {
    self->cs = cs;
    self->eof[0] = EOF;
    self->eof[1] = BOF;
}

static size_t _block_write(FILE *fp, block_t *block, uint8_t *s, uint8_t *e) {
    size_t rc;

    block->head.len = e - s;
    block->tail.cs = 0;
    for (uint8_t *p = s; p < e; ++p) block->tail.cs += *p;

    rc = fwrite(&block->head, sizeof(block->head), 1, fp);
    if (rc < 0) return rc;

    rc = fwrite(s, sizeof(uint8_t), e - s, fp);
    if (rc < 0) return rc;

    rc = fwrite(&block->tail, sizeof(block->tail), 1, fp);
    if (rc < 0) return rc;

    block->head.len = 0;
    block->tail.cs = 0;

    return rc;
}

int block_write(struct _pub_handler_t *handler, device_t *device, segment_e segment) {
    FILE *fp = handler->handle;
    block_params_t *args = handler->args;

    block_t block;
    uint8_t payload[0x1000 - sizeof(block)];
    hdb_header_t *hdb_header = (hdb_header_t *) payload;
    uint8_t *s = payload + sizeof(hdb_header_t), *e = payload + sizeof(payload);

    block_head_init(&block.head, bt_hdb, args->sched_time);
    block_tail_init(&block.tail, 0);
    hdb_header->dev_id = device->super.id;
    hdb_header->n_tags = 0;

    vector_t *tag_list = &device->_product->thing_model[segment];
    vector_t *val_list = &device->thing_value[segment];

    for (int i = 0; i < vector_size(val_list); ++i) {
        thing_model_t *tag = vector_get(tag_list, i);
        value_t *value = vector_get(val_list, i);

        if (value->_changed && value->timestamp > TIME_20100101) {
            if ((e - s) < (sizeof(tag_header_t) + sizeof(float))) {
                if (-1 == _block_write(fp, &block, payload, s)) return -1;

                hdb_header->n_tags = 0;
                s = payload + sizeof(hdb_header_t);
            }

            value->_changed = false;
            hdb_header->n_tags++;

            uint16_t tag_id = thing_model_tag_id(tag);
            log_info("lru=%d, tag=%d, value=%f", device->super.id, tag_id, value->value);

            tag_header_t *tag_header = (tag_header_t *) s;
            tag_header->tag_id = tag_id;
            tag_header->is_signed = true;
            tag_header->is_floating = true;
            tag_header->quality = value->quality;
            s += sizeof(tag_header_t);

            if (0.0f != value->value) {
                tag_header->value_len = sizeof(value->value);

                *(float *) s = value->value;
                s += sizeof(float);
            } else {
                tag_header->value_len = 0;
            }

            time_t delta = args->sched_time - value->timestamp;
            if (labs(delta) > 60) {//超过60s，记录采集时间戳
                tag_header->has_timestamp = true;

                *(uint32_t *) s = value->timestamp;
                s += sizeof(uint32_t);

                if (labs(delta) > 300) {//超过300秒，标记为oldData
                    tag_header->quality = oldData;
                }
            } else {
                tag_header->has_timestamp = false;
            }
        }
    }

    if (hdb_header->n_tags > 0) {
        if (-1 == _block_write(fp, &block, payload, s)) return -1;
    }

    return 0;
}

int block_flush(struct _pub_handler_t *handler) {
    FILE *fp = handler->handle;
    return fflush(fp);
}